/************************************************************************/
/*									*/
/*			   Copyright (C)				*/
/*			    Loquendo SpA				*/
/*			  All Rights Reserved				*/
/*									*/
/*   This file is a template for developing a custom audio destination	*/
/*	     Add your audio specific code when necessary 		*/
/*									*/
/************************************************************************/

#include <stdlib.h>
// Please do not remove this constant: it must precede the #include LoqAudioStub.h */
#define TTSINCLUDED_BY_AUDIODEST
#include "LoqAudioStub.h"

#define AUDIOSTUBMALLOC	    1
#define INVALIDPARAM	    2
// TODO: Add here your error codes

static void* pU = NULL;
void (*PutDataCb)(void* channel, void* pData, unsigned int nBytes, unsigned int* nSent, void* pUser);
void SetCb(void(*cb)(void* channel, void* pData, unsigned int nBytes, unsigned int* nSent, void* pUser), void* pUser)
{
	PutDataCb = cb;
	pU = pUser;
}

typedef struct {
    unsigned int SampleRate;
    char coding[10];
    const void *pUser;
    // TODO: Add here your member data
} LoquendoAudioStubChannelType;

ttspFuncType LoqAudioFile(ttsProcIdType procname, const void *pUser)
{
// Please do not modify this function
    static const struct {
	ttsProcIdType name;
	ttspFuncType func;
    } FuncTable[] = {
	{tts_GET_VERSION, (ttspFuncType)LoquendoAudioStubGetVersion},
	{TTSAUDIO_OPEN, (ttspFuncType)LoquendoAudioStubOpen},
	{TTSAUDIO_CLOSE, (ttspFuncType)LoquendoAudioStubClose},
	{TTSAUDIO_PUTDATA, (ttspFuncType)LoquendoAudioStubPutData},
	{TTSAUDIO_STOP, (ttspFuncType)LoquendoAudioStubStop},
	{TTSAUDIO_PAUSE, (ttspFuncType)LoquendoAudioStubPause},
	{TTSAUDIO_RESUME, (ttspFuncType)LoquendoAudioStubResume},
	{TTSAUDIO_GETERRORMESSAGE, (ttspFuncType)LoquendoAudioStubGetErrorMessage},
	{TTSAUDIO_CUSTOMOPEN, (ttspFuncType)LoquendoAudioStubCustomOpen}
    };
    unsigned int i,size=sizeof(FuncTable)/sizeof(FuncTable[0]);
    if(procname == tts_NO_PROC || size==0) return NULL;
    for(i=0;i<size;i++)
    {
	if(procname == FuncTable[i].name)
	    return FuncTable[i].func;
    }
    return NULL;
}
ttsGetProcTableAddrPointerType LoqAudioFileVirtualTable = LoqAudioFile;

ttsResultType LoquendoAudioStubGetVersion(char * strversion){
    // Please do not modify this function
    ttsGetVersionType This_is_for_checking_only;
    This_is_for_checking_only = LoquendoAudioStubGetVersion;
    strcpy(strversion,ttsVERSION);
    return tts_OK;
}

ttsResultType LoquendoAudioStubOpen(void **channel,const char *DeviceName, unsigned int SampleRate,const char *coding,ttsBoolType *bRealTime)
{
    // Please do not modify this function: this one is for backward compatibility
    ttsAudioOpenType This_is_for_checking_only;
    This_is_for_checking_only = LoquendoAudioStubOpen;
    return LoquendoAudioStubCustomOpen(channel,DeviceName,SampleRate,coding,bRealTime,NULL);
}

ttsResultType LoquendoAudioStubCustomOpen(void **channel,const char *DeviceName, unsigned int SampleRate,const char *coding,ttsBoolType *bRealTime, const void *pUser)
{
    // void **channel	      [OUT] audio destination channel
    // const char *DeviceName  [IN] audio destination device name (e.g. filename)
    // unsigned int SampleRate [IN] sampling rate in Hz
    // const char *coding      [IN] audio encoding (e.g. "l" for linear - "a" for alaw, etc.)
    // ttsBoolType *bRealTime [OUT] realtime capability (see below)
    // const void *pUser       [IN] this is for user specific data    
    LoquendoAudioStubChannelType *ch;
    ttsAudioCustomOpenType This_is_for_checking_only;
    ttsResultType r = tts_OK;
    // The following assignment is for realtime audio destinations (e.g audio boards)
    // Use ttsFALSE for NON-realtime audio destinations (e.g. audio files)
    // TODO: assign the correct value to *bRealTime
    if(NULL != bRealTime) *bRealTime = ttsTRUE;
    This_is_for_checking_only = LoquendoAudioStubCustomOpen;
    *channel = ch = (LoquendoAudioStubChannelType *)malloc(sizeof(LoquendoAudioStubChannelType));
	memset(ch,0,sizeof(LoquendoAudioStubChannelType));
    if(ch == NULL)
	return AUDIOSTUBMALLOC;
    if(coding==NULL || coding =='\0') 
	(void)strcpy(ch->coding,"l");
    else (void) strcpy(ch->coding,coding);
    ch->SampleRate = SampleRate;
    // TODO: Add here specific code for opening your audio destination
    return r;
}

ttsResultType LoquendoAudioStubClose(void *channel)
{
    // void *channel	    [IN]    audio destination channel
    ttsResultType r = tts_OK;
    LoquendoAudioStubChannelType *ch = channel;
    ttsAudioCloseType This_is_for_checking_only;
    This_is_for_checking_only = LoquendoAudioStubClose;
    if(ch==NULL) return tts_OK;
    // TODO: Add here specific code for closing your audio destination
    free(ch);
    return r;
}

ttsResultType LoquendoAudioStubPutData(void *channel,void *pData,unsigned int nBytes,unsigned int *nSent)
{
    // void *channel	    [IN]    audio destination channel
    // void *pData	    [IN]    audio sample buffer
    // unsigned int nBytes  [IN]    pData buffer length in bytes
    // unsigned int *nSent  [UNUSED]  do not use: reserved
    LoquendoAudioStubChannelType *ch = channel;

    ttsAudioPutDataType This_is_for_checking_only;
    This_is_for_checking_only = LoquendoAudioStubPutData;
    if(ch==NULL) return tts_OK;
    if(nSent) *nSent = 0;
    if(nBytes!=0)
    {
	// Loquendo TTS calls this function as far as an audio buffer is ready
	// TODO: Add here specific code for sending audio samples to your audio destination
	
	// If you return TTS_AUDIOFULL, Loquendo TTS will call this function again, with
	// the same audio buffer as parameter, until tts_OK is returned.
	// This is the best method to slow down Loquendo TTS (e.g. to avoid your internal
	// buffer overflow)
		if(PutDataCb)
		{
			PutDataCb(channel, pData, nBytes, nSent, pU);
		}
		if(nSent) *nSent = nBytes;
		return tts_OK;
    }
    else
    {
	// Loquendo TTS calls always this function once more with nBytes=0 
	// after all audio samples have been sent

	// TODO: Add here specific code for managing the end of an audio streaming
	
		return tts_OK;
    }
}

ttsResultType LoquendoAudioStubStop(void *channel)
{
    // void *channel	    [IN]    audio destination channel
    ttsResultType r = tts_OK;
    LoquendoAudioStubChannelType *ch = channel;
    ttsAudioStopType This_is_for_checking_only;
    This_is_for_checking_only = LoquendoAudioStubStop;
    if(ch==NULL) return tts_OK;
    // TODO: Add here specific code for stopping your audio destination
    return r;
}

ttsResultType LoquendoAudioStubPause(void *channel)
{
    // void *channel	    [IN]    audio destination channel
    ttsResultType r = tts_OK;
    LoquendoAudioStubChannelType *ch = channel;
    ttsAudioPauseType This_is_for_checking_only;
    This_is_for_checking_only = LoquendoAudioStubPause;
    if(ch==NULL) return tts_OK;
    // TODO: Add here specific code for pausing your audio destination
    return r;
}

ttsResultType LoquendoAudioStubResume(void *channel)
{
    // void *channel	    [IN]    audio destination channel
    ttsResultType r = tts_OK;
    LoquendoAudioStubChannelType *ch = channel;
    ttsAudioResumeType This_is_for_checking_only;
    This_is_for_checking_only = LoquendoAudioStubResume;
    if(ch==NULL) return tts_OK;
    // TODO: Add here specific code for resuming (after pause) your audio destination
    return r;
}

ttsResultType LoquendoAudioStubGetErrorMessage(ttsResultType ErrorCode,char *message,unsigned int size)
{
    // ttsResultType ErrorCode  [IN]	user-defined error code
    // char *message		[OUT]	user-defined error message
    // unsigned int size	[IN]	maximum number of characters to copy
 
    ttsResultType r = tts_OK;
    const char *pmes = NULL;
    ttsAudioGetErrorMessageType This_is_for_checking_only;
    This_is_for_checking_only = LoquendoAudioStubGetErrorMessage;
    if(message == NULL) return INVALIDPARAM;
    switch(ErrorCode)
    {
    case AUDIOSTUBMALLOC: pmes = "Memory error"; break;
    case INVALIDPARAM: pmes = "Invalid parameter"; break;
    // TODO: Add here your error strings
    default: pmes = "Unknown error"; break;
    }
    (void)strncpy(message,pmes,size-1);
    message[size-1]='\0';
    return r;
}

